﻿using System;
using System.Threading;
using System.Diagnostics;
using System.Xml;
using Microsoft.AnalysisServices;

namespace ASNetWin
{
    class ServerHealthMonitor
    {
        PerformanceCounter pcProcessor, pcMemUsage, pcMemHighLimit, pcMemLowLimit, pcDisk, pcNetwork;
        private float processor, memUsage, memHighLimit, memLowLimit, disk, network;
        private int CPUThreshold, networkThresholdMB, diskThreshold;
        private string ssasConnectionString;

        public ServerHealthMonitor()
        {
            //all this stuff comes from the config file
            XmlDocument xConf = new XmlDocument();
            xConf.Load("C:\\ASNet\\local_conf.xml");

            pcProcessor = new PerformanceCounter(
                    xConf.GetElementsByTagName("CPUCounter").Item(0).ChildNodes.Item(0).InnerText,
                    xConf.GetElementsByTagName("CPUCounter").Item(0).ChildNodes.Item(1).InnerText,
                    xConf.GetElementsByTagName("CPUCounter").Item(0).ChildNodes.Item(2).InnerText);
            pcMemUsage = new PerformanceCounter(
                    xConf.GetElementsByTagName("MemoryUsageKB").Item(0).ChildNodes.Item(0).InnerText,
                    xConf.GetElementsByTagName("MemoryUsageKB").Item(0).ChildNodes.Item(1).InnerText);
            pcMemHighLimit = new PerformanceCounter(
                    xConf.GetElementsByTagName("MemoryLimitHighKB").Item(0).ChildNodes.Item(0).InnerText,
                    xConf.GetElementsByTagName("MemoryLimitHighKB").Item(0).ChildNodes.Item(1).InnerText);
            pcMemLowLimit = new PerformanceCounter(
                    xConf.GetElementsByTagName("MemoryLimitLowKB").Item(0).ChildNodes.Item(0).InnerText,
                    xConf.GetElementsByTagName("MemoryLimitLowKB").Item(0).ChildNodes.Item(1).InnerText);
            pcDisk = new PerformanceCounter(
                    xConf.GetElementsByTagName("Disk").Item(0).ChildNodes.Item(0).InnerText,
                    xConf.GetElementsByTagName("Disk").Item(0).ChildNodes.Item(1).InnerText,
                    xConf.GetElementsByTagName("Disk").Item(0).ChildNodes.Item(2).InnerText);
            pcNetwork = new PerformanceCounter(
                    xConf.GetElementsByTagName("Network").Item(0).ChildNodes.Item(0).InnerText,
                    xConf.GetElementsByTagName("Network").Item(0).ChildNodes.Item(1).InnerText,
                    xConf.GetElementsByTagName("Network").Item(0).ChildNodes.Item(2).InnerText);

            CPUThreshold = Int16.Parse(xConf.GetElementsByTagName("CPUThreshold").Item(0).InnerText);
            networkThresholdMB = Int16.Parse(xConf.GetElementsByTagName("NetworkThresholdMB").Item(0).InnerText);
            diskThreshold = Int16.Parse(xConf.GetElementsByTagName("DiskThreshold").Item(0).InnerText);
            ssasConnectionString = xConf.GetElementsByTagName("SSASConnectionString").Item(0).InnerText;
        }

        // returns 0 for down and 1 for up
        private float getServerState()
        {
            Server svr = new Server();
            try
            {
                //connect-disconnect to SSAS
                svr.Connect(ssasConnectionString);
                svr.Disconnect();
                return 1;
            }
            catch (Exception)
            {
                return 0;
            }
        }

        //returns 0: server down; 1: busy; 2: free
        private int getCounterScore(string serverName, int counterWait)
        {
            //calling twice because first time it returns 0.0 - bing PerformanceCounter and check it on MSDN for a longer comment
            pcProcessor.NextValue();
            pcMemUsage.NextValue();
            pcMemHighLimit.NextValue();
            pcMemLowLimit.NextValue();
            pcDisk.NextValue();
            pcNetwork.NextValue();

            //we have to wait for the counters to get updated - 5 sec should also allow other processes trying to access the
            //cache to get a lock
            Thread.Sleep(counterWait);

            processor = pcProcessor.NextValue();
            memUsage = pcMemUsage.NextValue();
            memHighLimit = pcMemHighLimit.NextValue();
            memLowLimit = pcMemLowLimit.NextValue();
            disk = pcDisk.NextValue();
            network = pcNetwork.NextValue();

            if ((processor > CPUThreshold) ||
                    (network > (networkThresholdMB * 1024 * 1024)) ||
                    (disk > diskThreshold) ||
                //memory used above Mid Memory Point - this is not a customisable calculation as changing it can
                //easily cause problems
                    (memUsage > ((memHighLimit - memLowLimit) / 2 + memLowLimit)))
            {
                return 1;
            }
            else
            {
                return 2;
            }
        }

        //this is to combine the two methods above - used to access this class's functionality
        public int GetServerLoadKPI(string serverName, int counterWait)
        {
            if (getServerState() == 0)
            {
                return 0;
            }
            else
            {
                return getCounterScore(serverName, counterWait);
            }
        }
    }
}
